using System;
using System.Linq;
using LoggingMagic.AssemlyOperations;
using LoggingMagic.Injectors.Helpers;
using LoggingMagic.Injectors.StaticField.Parameters;
using Mono.Cecil;
using LoggingMagic.Extensions;
using Mono.Cecil.Cil;

namespace LoggingMagic.Injectors.StaticField.Base
{
    internal class StaticFieldMethodCallWithParamsInjector : StaticFieldMethodCallInjector
    {
        private readonly MethodParametersToArray _parametersToArray;

        public StaticFieldMethodCallWithParamsInjector(ModuleDefinition module, IStaticFieldParameters parameters, MethodParametersToArray parametersToArray)
            : base(module, parameters)
        {
            _parametersToArray = parametersToArray;
        }

        public override void Inject(MethodDefinition method, Instructions ops)
        {
            if (SkipMethod(method))
                return;

            #region Log.Logger.Info("Entering, params: {0}, {1}...")

            ops.Ldsfld(LoggingField);
            ops.Ldstr(EnteringText(method));
            ops.Ldloc(ParametersArray(method, ops));
            ops.Call(LoggingMethod);

            #endregion
        }

        protected VariableDefinition ParametersArray(MethodDefinition method, Instructions ops)
        {
            return _parametersToArray.Convert(method, ops);
        }

        protected override string EnteringText(MethodDefinition method)
        {
            var logString = "Entering(";
            if (method.Parameters.Count > 0)
            {
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    if (i > 0) logString += ", ";
                    logString += "'{" + i + "}'";
                }
            }
            logString += ")";
            return logString;
        }

        protected override MethodReference FindLoggingMethod(FieldDefinition field)
        {
            var loggingMethod = LoggingField.FieldType.Resolve().Methods.Where(
                x => x.FullName.MethodSignature() == _parameters.LoggingMethodWithParamsSignature).First();

            if (loggingMethod == null)
                throw new InvalidOperationException(String.Format("LoggingMethod with signature {0} not found", _parameters.LoggingMethodSignature));

            return _module.Import(loggingMethod);
        }

    }
}